package handlers

import (
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/labstack/echo/v4"

	"night-school-api/database"
	"night-school-api/models"
	"night-school-api/utils"
)

// 获取课程分类
func GetCourseCates(c echo.Context) error {
	var total int64
	db := database.DB
	db.Model(&models.CourseCategory{}).Count(&total)

	var cates []models.CourseCategory
	page, size := utils.GetPagination(c)
	db.Model(&models.CourseCategory{}).Limit(size).Offset((page - 1) * size).Find(&cates)

	return utils.JSONPagination(c, page, size, total, cates)
}

// 获取所有下辖区
func GetCounties(c echo.Context) error {
	page, size := utils.GetPagination(c)

	var total int64
	total = int64(len(utils.CountyMap))

	data := make([]map[string]interface{}, len(utils.Counties))
	for i, county := range utils.Counties {
		data[i] = map[string]interface{}{
			"index": i,
			"name":  county,
		}
	}
	// fmt.Println(fmt.Sprintf("utils.CountyMap: %+v", data))

	return utils.JSONPagination(c, page, size, total, data)
}

func GetCourses(c echo.Context) error {
	u := c.Get("uid")
	var uid int
	if u != nil {
		uid = u.(int)
	} else {
		uid = 0
	}
	c.Logger().Info("GetCourses uid: " + strconv.Itoa(uid))

	// 分类id
	cateId, err := strconv.Atoi(c.QueryParam("cate_id"))
	if err != nil {
		cateId = 0
	}

	// 县级区划索引
	countyIndex, err := strconv.Atoi(c.QueryParam("county_index"))
	if err != nil {
		countyIndex = -1
	} else {
		if countyIndex < 0 || countyIndex >= len(utils.Counties) {
			countyIndex = -1
		}
	}

	hot := c.QueryParam("hot")
	finished := c.QueryParam("finished")
	keywords := c.QueryParam("keywords")

	db := database.DB
	query := db.Model(&models.Course{}).Where("status = ?", models.AuditApproved)
	if cateId > 0 {
		query = query.Where("cate_id = ?", cateId)
	}
	if countyIndex > 0 {
		query = query.Where("county_index =?", countyIndex)
	}

	// 未使用关键字搜索时，根据 finished 字段来决定显示未结束或已结束的课程
	now := time.Now().In(models.TimeLocation)
	if finished == "yes" {
		query = query.Where("end_at <?", now)
	} else {
		// query = query.Where("end_at >=?", now)
	}

	if keywords != "" {
		query = query.Where(
			db.Where("name LIKE ?", "%"+keywords+"%").Or("introduction LIKE?", "%"+keywords+"%"),
		)
	}

	var order string
	if hot == "yes" {
		order = "enroll_amount DESC"
	} else {
		order = "id DESC"
	}

	var total int64
	var courses []models.CourseRecord
	query.Count(&total)
	page, size := utils.GetPagination(c)
	query.Preload("CourseCategory").Order(order).Limit(size).Offset((page - 1) * size).Find(&courses)

	if uid > 0 {
		for i := range courses {
			course := courses[i]
			var enrollment models.Enrollment
			db.Model(&models.Enrollment{}).Where("course_id =? AND user_id =?", course.ID, uid).Find(&enrollment)

			if enrollment.ID > 0 {
				courses[i].MyEnrollment = enrollment
			}
		}
	}

	return utils.JSONPagination(c, page, size, total, courses)
}

// 已报名的课程
func MyCourses(c echo.Context) error {
	u := c.Get("uid")
	var uid int
	if u != nil {
		uid = u.(int)
	} else {
		uid = 0
	}
	// c.Logger().Info("MyCourses uid: " + strconv.Itoa(uid))

	tabInt, err := strconv.Atoi(c.QueryParam("tab"))
	var tab int
	if err != nil {
		tab = 0
	} else {
		tab = tabInt
	}

	if tab < 0 || tab > 2 {
		return utils.JSONError(c, "请求参数不合法")
	}

	page, size := utils.GetPagination(c)

	db := database.DB
	query := db.Table("courses").InnerJoins("inner join enrollments on enrollments.course_id = courses.id")
	query = query.Where("enrollments.user_id =?", uid)

	// 未使用关键字搜索时，根据 finished 字段来决定显示未结束或已结束的课程
	now := time.Now().In(models.TimeLocation)

	// tab  0：已报名课程，1：已审核通过，并且未结束的，2：已审核通过，并且已结束的，
	if tab == 1 {
		query = query.Where("enrollments.status =?", 2)
		query = query.Where("start_at < ?", now).Where("end_at > ?", now)
	} else if tab == 2 {
		query = query.Where("enrollments.status =?", 2)
		query = query.Where("end_at <= ?", now)
	}

	order := "id DESC"

	var total int64
	var courses []models.CourseRecord
	query.Count(&total)
	query.Preload("CourseCategory").Order(order).Limit(size).Offset((page - 1) * size).Find(&courses)

	if uid > 0 {
		for i := range courses {
			course := courses[i]
			// c.Logger().Info(fmt.Sprintf("%T (%v)", course, course))
			var enrollment models.Enrollment
			db.Model(&models.Enrollment{}).Where("course_id =? AND user_id =?", course.ID, uid).Find(&enrollment)

			if enrollment.ID > 0 {
				courses[i].MyEnrollment = enrollment
			}
		}
	}

	return utils.JSONPagination(c, page, size, total, courses)
}

// 作为老师的课程
func TeacherCourses(c echo.Context) error {
	u := c.Get("uid")
	var uid int
	if u != nil {
		uid = u.(int)
	} else {
		uid = 0
	}
	// c.Logger().Info("GetCourses uid: " + strconv.Itoa(uid))

	tabInt, err := strconv.Atoi(c.QueryParam("tab"))
	var tab int
	if err != nil {
		tab = 0
	} else {
		tab = tabInt
	}

	if tab < 0 || tab > 2 {
		return utils.JSONError(c, "请求参数不合法")
	}

	page, size := utils.GetPagination(c)

	db := database.DB
	query := db.Table("courses").Where("user_id =?", uid)

	// 未使用关键字搜索时，根据 finished 字段来决定显示未结束或已结束的课程
	now := time.Now().In(models.TimeLocation)

	// tab  0：作为老师的课程, 1：作为老师的课程，已审核通过，并且未结束的，2：作为老师的课程，已审核通过，并且已结束的，
	if tab == 1 {
		query = query.Where("status =?", 2)
		query = query.Where("start_at < ?", now).Where("end_at > ?", now)
	} else if tab == 2 {
		query = query.Where("status =?", 2)
		query = query.Where("end_at <= ?", now)
	}

	order := "id DESC"

	var total int64
	var courses []models.CourseWithEnrollmentAndComment
	query.Count(&total)
	query.Preload("CourseCategory").Order(order).Limit(size).Offset((page - 1) * size).Find(&courses)

	var (
		enrollment_amount int64
	)

	for i := range courses {
		db.Model(&models.Enrollment{}).Where("course_id =?", courses[i].ID).Count(&enrollment_amount)
		courses[i].Enrollment.Count = int(enrollment_amount)
	}

	return utils.JSONPagination(c, page, size, total, courses)
}

func CourseDetail(c echo.Context) error {
	u := c.Get("uid")
	var uid int
	if u != nil {
		uid = u.(int)
	} else {
		uid = 0
	}
	// c.Logger().Info("GetCourses uid: " + strconv.Itoa(uid))

	id, err := strconv.Atoi(c.QueryParam("id"))
	if err != nil || id <= 0 {
		return utils.JSONError(c, "参数错误")
	}

	db := database.DB

	query := db.Model(&models.Course{})

	var course models.CourseRecord
	query.Preload("CourseCategory").First(&course, id)
	if course.ID <= 0 {
		return utils.JSONError(c, "课程不存在")
	}
	if course.Status != models.AuditApproved {
		return utils.JSONError(c, "课程未审核通过")
	}

	if uid > 0 {
		// 更新访问量
		fmt.Println(fmt.Sprintf("course visit_amount: %d", course.VisitAmount))
		db.Debug().Model(&models.Course{}).Where("id =?", course.ID).Update("visit_amount", (course.VisitAmount + 1))

		var enrollment models.Enrollment
		db.Model(&models.Enrollment{}).Where("course_id =? AND user_id =?", course.ID, uid).Find(&enrollment)

		if enrollment.ID > 0 {
			course.MyEnrollment = enrollment
		}
	}

	return utils.JSONSuccess(c, course, "获取成功")
}

func CreateCourse(c echo.Context) error {
	uid := c.Get("uid").(int)

	var req models.Course

	// 解析 JSON 请求
	if err := c.Bind(&req); err != nil {
		return utils.JSONError(c, "参数错误"+err.Error())
	}

	if err := c.Validate(&req); err != nil {
		return err
	}

	// 检查区县
	addressJson := req.Address
	var addr map[string]interface{}
	err := json.Unmarshal([]byte(addressJson), &addr)
	if err != nil {
		return utils.JSONError(c, "课程地址格式错误")
	}

	var addressStr string
	addressStr, ok := addr["address"].(string)
	if !ok {
		return utils.JSONError(c, "课程详细地址格式错误")
	}

	countyIndex := utils.GetCountyIndexFromAddress(addressStr)
	c.Logger().Info("address: " + addressStr + " " + "countyIndex: " + strconv.Itoa(countyIndex))

	if countyIndex < 0 || countyIndex >= len(utils.Counties) {
		return utils.JSONError(c, fmt.Sprintf("课程地址不在%s范围内，请重新选择地址", utils.CityName))
	} else {
		req.CountyIndex = int(countyIndex)
	}

	// 检查上课时间
	courseTimeJson := req.CourseTime
	var courseTimeList []map[string]interface{}
	err = json.Unmarshal([]byte(courseTimeJson), &courseTimeList)
	if err != nil {
		return utils.JSONError(c, "上课时间格式错误")
	}

	var startAt, endAt time.Time
	for _, item := range courseTimeList {
		startAtStr, ok := item["start_time"].(string)
		if !ok {
			continue
		}

		startAtTmp, err := time.ParseInLocation("2006-01-02 15:04", startAtStr, models.TimeLocation)
		if err != nil {
			continue
		}
		if startAt.IsZero() || startAtTmp.Before(startAt) {
			startAt = startAtTmp
		}

		endAtStr, ok := item["end_time"].(string)
		if !ok {
			continue
		}
		// fmt.Printf("endAtStr: %v (%T)\n", endAtStr, endAtStr)

		endAtTmp, err := time.ParseInLocation("2006-01-02 15:04", endAtStr, models.TimeLocation)
		if err != nil {
			continue
		}
		if endAtTmp.After(endAt) {
			endAt = endAtTmp
		}
	}

	if startAt.IsZero() || endAt.IsZero() {
		return utils.JSONError(c, "上课时间格式错误")
	} else {
		// 设置课程开始和结束时间
		req.StartAt = models.JSONTimeNoSeconds{Time: startAt}
		req.EndAt = models.JSONTimeNoSeconds{Time: endAt}
	}

	if req.EnrollEndAt.After(req.EndAt.Time) {
		return utils.JSONError(c, "报名截止时间不能晚于课程结束时间")
	}

	db := database.DB

	var count int64
	db.Model(&models.CourseCategory{}).Where("id = ?", req.CateId).Count(&count)
	if count <= 0 {
		return utils.JSONError(c, "课程分类不存在")
	}

	req.UserID = uid

	result := db.Create(&req)

	if result.Error != nil {
		c.Logger().Info("创建课程失败: " + result.Error.Error())
		return utils.JSONError(c, "创建课程失败")
	} else {
		data := map[string]int{
			"id": req.ID,
		}
		return utils.JSONSuccess(c, data, "创建课程成功，请等待管理员审核")
	}
}
